﻿Namespace Imaging

    Public Interface IHDRBitmap
        ReadOnly Property Chanel1() As Double
        ReadOnly Property Chanel2() As Double
        ReadOnly Property Chanel3() As Double

        ReadOnly Property Width() As Integer
        ReadOnly Property Height() As Integer

    End Interface

    Public Class HDRBitmap

        Protected _Width As Integer
        Protected _Height As Integer
        Protected _GammaCorrection As Double = 2.2
        Protected _BufferX() As Double
        Protected _BufferY() As Double
        Protected _BufferZ() As Double

        Sub New(ByVal Width As Integer, ByVal Height As Integer)
            _Height = Height
            _Width = Width
            ReDim _BufferX(0 To _Width * _Height - 1)
            ReDim _BufferY(0 To _Width * _Height - 1)
            ReDim _BufferZ(0 To _Width * _Height - 1)
        End Sub

        Sub New(ByVal bmp As GDIBitmap)
            Me.New(bmp.Width, bmp.Height)

            Dim yOfs As Integer
            Dim xOfs As Integer
            Dim RGB As RGBTriplet
            Dim XYZ As XYZTriplet

            For y As Integer = 0 To _Height - 1
                yOfs = y * _Width
                For x As Integer = 0 To _Width - 1
                    xOfs = yOfs + x
                    RGB = New RGBTriplet(bmp.RawData(xOfs * bmp.PixelSize + 2) / 255.0, _
                                         bmp.RawData(xOfs * bmp.PixelSize + 1) / 255.0, _
                                         bmp.RawData(xOfs * bmp.PixelSize) / 255.0)
                    XYZ = ColorSpaceConverter.RGB2XYZ(RGB)
                    _BufferX(xOfs) = XYZ.X
                    _BufferY(xOfs) = XYZ.Y
                    _BufferZ(xOfs) = XYZ.Z
                Next
            Next
        End Sub

        Public ReadOnly Property X() As Double()
            Get
                Return _BufferX
            End Get
        End Property

        Public ReadOnly Property Y() As Double()
            Get
                Return _BufferY
            End Get
        End Property

        Public ReadOnly Property Z() As Double()
            Get
                Return _BufferZ
            End Get
        End Property

        Public ReadOnly Property Width() As Integer
            Get
                Return _Width
            End Get
        End Property

        Public ReadOnly Property Height() As Integer
            Get
                Return _Height
            End Get
        End Property

        Public Property GammaCorrection() As Double
            Get
                Return _GammaCorrection
            End Get
            Set(ByVal value As Double)
                _GammaCorrection = value
            End Set
        End Property

        Public Function AsBitmap(ByVal GammaCorrection As Double) As Drawing.Bitmap
            Dim Bmp As New Drawing.Bitmap(_Width, _Height, Drawing.Imaging.PixelFormat.Format24bppRgb)
            Dim tmpGDI As New GDIBitmap(Bmp)
            Dim ofs As Integer
            Dim RGB As RGBTriplet

            For y As Integer = 0 To _Height - 1
                For x As Integer = 0 To _Width - 1
                    ofs = y * _Width + x
                    RGB = ColorSpaceConverter.XYZ2RGB(_BufferX(ofs), _BufferY(ofs), _BufferZ(ofs))
                    If GammaCorrection <> 1 Then
                        RGB.Red = RGB.Red ^ (1 / GammaCorrection)
                        RGB.Green = RGB.Green ^ (1 / GammaCorrection)
                        RGB.Blue = RGB.Blue ^ (1 / GammaCorrection)
                    End If
                    tmpGDI.Pixel2(x, y) = ColorSpaceConverter.RGB2Color(RGB)
                Next
            Next

            Return tmpGDI.UnLockBitmap
        End Function

        Public Function AsBitmap() As Drawing.Bitmap
            Return AsBitmap(_GammaCorrection)
        End Function

        Public Property Pixel(ByVal x As Integer, ByVal y As Integer) As XYZTriplet
            Get
                Return Pixel(Math.Max(Math.Min(y, _Height - 1), 0) * _Width + Math.Max(Math.Min(x, _Width - 1), 0))
            End Get
            Set(ByVal value As XYZTriplet)
                Pixel(Math.Max(Math.Min(y, _Height - 1), 0) * _Width + Math.Max(Math.Min(x, _Width - 1), 0)) = value
            End Set
        End Property

        Public Property Pixel(ByVal Ofs As Integer) As XYZTriplet
            Get
                Return New XYZTriplet(_BufferX(Ofs), _BufferY(Ofs), _BufferZ(Ofs))
            End Get
            Set(ByVal value As XYZTriplet)
                _BufferX(Ofs) = value.X
                _BufferY(Ofs) = value.Y
                _BufferZ(Ofs) = value.Z
            End Set
        End Property

        Public Property PixelAsRGB(ByVal x As Integer, ByVal y As Integer) As RGBTriplet
            Get
                Return PixelAsRGB(Math.Max(Math.Min(y, _Height - 1), 0) * _Width + Math.Max(Math.Min(x, _Width - 1), 0))
            End Get
            Set(ByVal value As RGBTriplet)
                PixelAsRGB(y * _Width + x) = value
            End Set
        End Property

        Public Property PixelAsRGB(ByVal Ofs As Integer) As RGBTriplet
            Get
                Return ColorSpaceConverter.XYZ2RGB(_BufferX(Ofs), _BufferY(Ofs), _BufferZ(Ofs))
            End Get
            Set(ByVal value As RGBTriplet)
                Dim XYZ As XYZTriplet = ColorSpaceConverter.RGB2XYZ(value)
                _BufferX(Ofs) = XYZ.X
                _BufferY(Ofs) = XYZ.Y
                _BufferZ(Ofs) = XYZ.Z
            End Set
        End Property

        Public Property PixelAsLab(ByVal x As Integer, ByVal y As Integer) As LabTriplet
            Get
                Return PixelAsLab(Math.Max(Math.Min(y, _Height - 1), 0) * _Width + Math.Max(Math.Min(x, _Width - 1), 0))
            End Get
            Set(ByVal value As LabTriplet)
                PixelAsLab(Math.Max(Math.Min(y, _Height - 1), 0) * _Width + Math.Max(Math.Min(x, _Width - 1), 0)) = value
            End Set
        End Property

        Public Property PixelAsLab(ByVal Ofs As Integer) As LabTriplet
            Get
                Return ColorSpaceConverter.XYZ2Lab(_BufferX(Ofs), _BufferY(Ofs), _BufferZ(Ofs))
            End Get
            Set(ByVal value As LabTriplet)
                Dim XYZ As XYZTriplet = ColorSpaceConverter.Lab2XYZ(value)
                _BufferX(Ofs) = XYZ.X
                _BufferY(Ofs) = XYZ.Y
                _BufferZ(Ofs) = XYZ.Z
            End Set
        End Property

        Public Property PixelAsHSV(ByVal x As Integer, ByVal y As Integer) As HSVTriplet
            Get
                Return PixelAsHSV(Math.Max(Math.Min(y, _Height - 1), 0) * _Width + Math.Max(Math.Min(x, _Width - 1), 0))
            End Get
            Set(ByVal value As HSVTriplet)
                PixelAsHSV(Math.Max(Math.Min(y, _Height - 1), 0) * _Width + Math.Max(Math.Min(x, _Width - 1), 0)) = value
            End Set
        End Property

        Public Property PixelAsHSV(ByVal Ofs As Integer) As HSVTriplet
            Get
                Return ColorSpaceConverter.XYZ2HSV(_BufferX(Ofs), _BufferY(Ofs), _BufferZ(Ofs))
            End Get
            Set(ByVal value As HSVTriplet)
                Dim XYZ As XYZTriplet = ColorSpaceConverter.HSV2XYZ(value)
                _BufferX(Ofs) = XYZ.X
                _BufferY(Ofs) = XYZ.Y
                _BufferZ(Ofs) = XYZ.Z
            End Set
        End Property

    End Class
End Namespace

